//package cn.skyquant.quant4j.jforex.strategy;
//
//
//import cn.skyquant.quant4j.sdk.util.constant.EAConstants;
//import cn.skyquant.quant4j.jforex.sdk.enums.LabelType;
//import cn.skyquant.quant4j.jforex.sdk.enums.OpenType;
//import cn.skyquant.quant4j.sdk.util.strategy.*;
//import com.alibaba.fastjson.JSONObject;
//import com.dukascopy.api.*;
//
//import java.math.BigDecimal;
//import java.math.RoundingMode;
//import java.util.*;
///* 雅典娜
// * 多货币策略
// * @author harley-dog
// */
//@Library("quant4j-tools-1.0.jar;guava-19.0.jar;httpclient-4.5.2.jar;httpcore-4.4.4.jar;fastjson-1.2.41.jar")
//public class Athena extends BaseStrategy {
//    @Configurable("是否开单")
//    public boolean isTrade = true;
//    @Configurable("是否需要补单")
//    public boolean replenish = false;
//    @Configurable("是否打印业务日志")
//    public boolean log_print = false;
//    @Configurable("是否合并订单")
//    public boolean is_merge = true;
//    @Configurable("止损平仓后暂停时间(小时)")
//    public Integer sl_sleep_time = 24;
//    @Configurable("首仓间隔时间(分钟)")
//    public Integer f_sleep_time = 5;
//    @Configurable("货币组0,数列0,倍率0,强制0,止损0")
//    public String str0 = "";
//    @Configurable("货币组1,数列1,倍率1,强制1,止损1")
//    public String str1 = "31,32,1,3,950";
//    @Configurable("货币组2,数列2,倍率2,强制2,止损2")
//    public String str2 = "";
//    @Configurable("货币组3,数列3,倍率3,强制3,止损3")
//    public String str3 = "33,34,1,4,1400";
//    @Configurable("货币组4,数列4,倍率4,强制4,止损4")
//    public String str4 = "";
//    @Configurable("货币组5,数列5,倍率5,强制5,止损5")
//    public String str5 = "";
//    @Configurable("货币组6,数列6,倍率6,强制6,止损6")
//    public String str6;
//    @Configurable("货币组7,数列7,倍率7,强制7,止损7")
//    public String str7;
//    @Configurable("货币组8,数列8,倍率8,强制8,止损8")
//    public String str8;
//    @Configurable("货币组9,数列9,倍率9,强制9,止损9")
//    public String str9;
//
//    //主方法
//    public void begin(BaseConfig symbolSeries,Instrument instrument, long time) {
//        Long sleepTime = this.closeTimeMap.get(symbolSeries.index);
//        if(sleepTime!=null && sleepTime.longValue()>0){
//            if(time<sleepTime){
//                return;
//            }
//        }
//        //先获取所有订单信息
//        List<IOrder> orderList = null;
//        try {
//            orderList = engine.getOrders();
//        } catch (JFException e) {
//            err.println("getOrders error:" + e.getMessage());
//            return;
//        }
//        Set<String> labelSet = new LinkedHashSet<>();
//        List<OrderEx> orderExList = new ArrayList<>();
//        if (orderList != null) {
//            for (IOrder order : orderList) {
//                String label = order.getLabel();
//                labelSet.add(label);
//                OrderEx orderEx = new OrderEx(order);
//                if(orderEx.valid(getName()) && orderEx.configIndex.equals(symbolSeries.index)){
//                    orderExList.add(orderEx);
//                }
//            }
//        }
//        process(instrument,time,symbolSeries,orderExList,labelSet);
//    }
//
//    //单个配置运行
//    public void process(Instrument instrument, long time, BaseConfig symbolSeries, List<OrderEx> orderExList, Set<String> labelSet) {
//        //执行开首仓逻辑
//        if (orderExList == null || orderExList.isEmpty() && isTrade) {
//            openOrder(symbolSeries, 0, OpenType.P, time, 0,orderExList,"open first order",null);//开首仓
//            return;
//        }
//        Double total = 0d;
//        OrderEx lastOrder0 = null;//寻找最后的0号订单
//        BaseOrderComment lastOrderComment = null;
//        String lastComment = null;
//        int index = -1;//用0号订单判断当前开到第几仓
//        for (OrderEx orderEx : orderExList) {
//            total += orderEx.order.getProfitLossInUSD();
//            if(orderEx.instrument != instrument){
//                continue;
//            }
//            if (orderEx.seriesIndex > index) {
//                index = orderEx.seriesIndex;
//                lastOrder0 = orderEx;
//                lastOrderComment = orderEx.orderComment;
//                lastComment = orderEx.order.getComment();
//            }
//        }
//        int total_int = total.intValue();
//        //止损
//        if (total_int <= symbolSeries.totalsl) {
//            closeOrdersWithTest(symbolSeries,orderExList, lastOrderComment,"config:" + symbolSeries.index + " loss:" + total + " <= " + symbolSeries.totalsl,time);
//            closeTimeMap.put(symbolSeries.index,time+ sl_sleep_time *60000);
//            return;
//        }
//        //止盈
//        if (lastOrderComment != null && total_int >= lastOrderComment.this_tp_money) {
//            closeOrdersWithTest(symbolSeries,orderExList, lastOrderComment,"config:" + symbolSeries.index + " profit:" + total + " >= " + lastOrderComment.this_tp_money,time);
//            closeTimeMap.put(symbolSeries.index,time+f_sleep_time*60000);
//            return;
//        }
//        //如果设置不开单，或者没有找到lastOrder则直接退出
//        if( !isTrade || lastOrder0==null){
//            return;
//        }
//        boolean canAdd = true;
//        //如果需要补单
//        if(replenish && lastComment!=null){
//            canAdd = replenishOrder(symbolSeries,index,orderExList,lastComment,time);
//        }
//        if(!canAdd){
//            return;
//        }
//        //强制加仓
//        if (lastOrderComment != null && total_int <= lastOrderComment.next_add_money_f && index < symbolSeries.seriesMultiList.size() - 1) {
//            String reason = "config:" + symbolSeries.index + " force add, lastOrderComment= " + lastOrderComment
//                    + ", total= " + total_int + " <= " + lastOrderComment.next_add_money_f + ",lastOrderEx=" + lastOrder0;
//            openOrder(symbolSeries, index + 1, OpenType.Q, time, total_int,orderExList,reason,lastOrderComment);
//            return;
//        }
//        long diff = time - (lastOrder0==null?0:lastOrder0.order.getCreationTime());
//        //普通加仓
//        if (lastOrderComment != null
//                && total_int <= lastOrderComment.next_add_money
//                && diff >= lastOrderComment.next_add_pause_time * 60000
//                && index < symbolSeries.seriesMultiList.size() - 1) {
//            String reason = "config:" + symbolSeries.index + " normal add, lastOrderComment= " + lastOrderComment
//                    + ", total= " + total_int + " <= " + lastOrderComment.next_add_money + ",diff=" + diff / 60000 + " >next_add_pause_time:" + lastOrderComment.next_add_pause_time;
//            openOrder(symbolSeries, index + 1, OpenType.P, time, total_int,orderExList,reason,lastOrderComment);
//        }
//    }
//
//    //补单程序
//    private boolean replenishOrder(BaseConfig symbolSeries,int index,List<OrderEx> orderExList,String lastOrderComment,long time) {
//        if (symbolSeries.valid == false || index < 0 || index >= symbolSeries.seriesMultiList.size() || lastOrderComment==null) {
//            return false;
//        }
//        //当前开到第index仓，那么根据规则，计算这一仓，所有的货币是否满足
//        List<ForexConfigSymbolGroup> forexConfigSymbolGroupList = symbolSeries.symbolGroupList;
//        ForexConfigSeriesMulti seriesMulti = symbolSeries.seriesMultiList.get(index);
//
//        boolean result = true;
//        for(ForexConfigSymbolGroup symbolGroup:forexConfigSymbolGroupList){
//            int expect = symbolGroup.standardPosition * seriesMulti.prssum;//在这一仓应该有这么多仓位
//            double actlyd = 0;
//            for(OrderEx orderEx:orderExList){
//                if(orderEx.instrument==symbolGroup.instrument
//                        && orderEx.configIndex.equals(symbolSeries.index)
//                        && orderEx.orderCommand==symbolGroup.orderCommand){
//                    actlyd+=orderEx.order.getAmount();
//                }
//            }
//            int actly = new BigDecimal(actlyd).multiply(EAConstants.MILLION).setScale(0, RoundingMode.HALF_UP).intValue();
//            int diff = expect - actly;
//            if(diff>=1000){
//                result = false;
//                int histOrderNum = getHistoryOrder(symbolSeries,time);
//                if(histOrderNum>0){
//                    if (log_print)
//                        out.println("config:" + symbolSeries.index + " find " + histOrderNum + " history orders in " + f_sleep_time + "mins，can not open replenishOrder:"+index);
//                    return false;
//                }
//                int trade = diff/1000*1000;
//                out.println("config:"+symbolSeries.index+",index:"+index+",instrument:"+symbolGroup.instrument+" type:"+symbolGroup.orderCommand
//                        +", expected"+expect+" unit,actually has "+actly+" unit,less than "+diff+" unit,need replenishOrder + "+trade+" unit");
//                IEngine.OrderCommand orderCommand = symbolGroup.orderCommand;
//                try {
//                    OrderEx rOrderEx = new OrderEx(getName(),LabelType.N,symbolSeries.index,index,symbolGroup.instrument,orderCommand);
//                    double rAmount = new BigDecimal(trade).divide(EAConstants.MILLION).doubleValue();
//                    engine.submitOrder(rOrderEx.toStringDiff(), symbolGroup.instrument, orderCommand, rAmount, 0, symbolGroup.slippage, 0, 0, 0, lastOrderComment);
//                } catch (JFException e) {
//                    out.println("replenishOrder error:"+symbolGroup.instrument+",type="+orderCommand+",replenish "+diff+":"+e );
//                }
//            }
//        }
//        return result;
//    }
//
//    //开仓
//    public void openOrder(BaseConfig symbolSeries, int index, OpenType openType, long time, int slmoney, List<OrderEx> orderExList, String reason, BaseOrderComment lastOrderComment) {
//        //前期校验
//        if (symbolSeries.valid == false || index < 0 || index >= symbolSeries.seriesMultiList.size()) {
//            return;
//        }
//        List<ForexConfigSymbolGroup> symbolGroupList = symbolSeries.symbolGroupList;
//        Map<Instrument,ITick> lastTickMap = new HashMap<>();
//        for(ForexConfigSymbolGroup symbolGroup:symbolGroupList){
//            Instrument instrument = symbolGroup.instrument;
//            ITick tick = null;
//            try {
//                tick = history.getLastTick(instrument);
//            } catch (JFException e) {
//                out.println("get "+instrument+" tick error:"+e.getMessage());
//                return;
//            }
//            if(tick==null){
//                out.println(instrument.name()+",tick is null");
//                return;
//            }
//            double ask_bid = tick.getAsk() - tick.getBid();
//            if(tick.getAsk()>symbolGroup.upperLimit){
//                if(log_print)
//                    out.println(instrument.name()+",ask:"+tick.getAsk()+" > upplerLimit:"+symbolGroup.upperLimit+", can't open order");
//                return;
//            }
//            if(tick.getBid() < symbolGroup.lowerLimit){
//                if(log_print)
//                    out.println(instrument.name()+",ask:"+tick.getBid()+" < lowerLimit:"+symbolGroup.lowerLimit+", can't open order");
//                return;
//            }
//            if(ask_bid > symbolGroup.maxSpread.doubleValue()){
//                if(log_print)
//                    out.println(instrument.name()+",ask:"+tick.getAsk()+" - bid:"+tick.getBid()+"="+String.format("%.5f",ask_bid)
//                            +" > maxSpread:"+String.format("%.5f",symbolGroup.maxSpread)+", can't open order");
//                return;
//            }
//            lastTickMap.put(instrument,tick);
//        }
//
//        int histOrderNum = getHistoryOrder(symbolSeries,time);
//        if(histOrderNum>0){
//            if (log_print)
//                out.println("config:" + symbolSeries.index + " find " + histOrderNum + " history orders in " + f_sleep_time + "mins，can not open "+openType+" order:"+index);
//            return;
//        }
//
//        out.println("config:" + symbolSeries.index + " open " + openType.value + " position, index:" + index+","+reason);
//        ForexConfigSeriesMulti seriesMulti = symbolSeries.seriesMultiList.get(index);
//        int this_tp_money = seriesMulti.tp;
//        int next_add_money = index == symbolSeries.seriesMultiList.size() - 1 ? 0 : symbolSeries.seriesMultiList.get(index + 1).sl;
//        int next_add_money_f = index == symbolSeries.seriesMultiList.size() - 1 ? 0 : symbolSeries.seriesMultiList.get(index + 1).slf;
//        int next_add_pause_time = index == symbolSeries.seriesMultiList.size() - 1 ? 0 : seriesMulti.time;
//
//        List<IOrder> orderList = new ArrayList<>();
//        int first_equit = lastOrderComment==null?new Double(this.context.getAccount().getEquity()).intValue():lastOrderComment.first_equit;
//        long first_time = lastOrderComment==null?time:lastOrderComment.first_time;
//        //先开1号，如果1号开成功了，再开其他的单子，否则其他的单子也不要开了
//        ForexConfigSymbolGroup symbol0 = symbolSeries.symbolGroupList.get(0);
//        IEngine.OrderCommand orderCommand0 = symbol0.orderCommand;
//        BigDecimal srcAmount0 = new BigDecimal(symbol0.standardPosition * symbolSeries.multiple * seriesMulti.prs);
//        double amount0 = srcAmount0.divide(EAConstants.MILLION).doubleValue();
//        OrderEx orderEx0 = new OrderEx(getName(),LabelType.N, symbolSeries.index, index, symbol0.instrument,orderCommand0);
//        String label0 = orderEx0.toStringDiff();
//        BaseOrderComment orderComment0 = new BaseOrderComment(index, openType, slmoney, this_tp_money, next_add_money, next_add_money_f, next_add_pause_time,first_equit,first_time);
//        String comment0 = orderComment0.toStringDiff();
//        IOrder order0 = null;
//        boolean canOpenOtherOrders = false;
//        try{
//            ITick tick = lastTickMap.get(symbol0.instrument);
//            if (tick == null) {
//                return;
//            }
//            if (log_print)
//                out.println("label=" + label0 + ",symbol=" + symbol0.instrument.name() + ",orderCommand=" + orderCommand0 + ",srcAmount=" + srcAmount0 + ",amount=" + amount0 + ",slippage=" + symbol0.slippage  + ",comment=" + comment0);
//            order0 = engine.submitOrder(label0, symbol0.instrument, orderCommand0, amount0, 0, symbol0.slippage, 0, 0, 0, comment0);
//            if(order0!=null){
//                order0.waitForUpdate(EAConstants.waitOrderTime, IOrder.State.FILLED);
//            }
//            if(order0.getState()== IOrder.State.FILLED){
//                canOpenOtherOrders = true;
//                orderList.add(order0);
//            }
//        }catch (JFException e){
//            err.println("config:"+symbolSeries+",index:"+index+",Order 0,error:" + e.getMessage());
//        }
//        //如果1号订单都没开成功，其他的也不要开了
//        if(!canOpenOtherOrders){
//            return;
//        }
//        //如果1号开成功了，其他的异步开单，开不成功的话，用补单来解决
//        for (int k=1;k<symbolSeries.symbolGroupList.size();k++) {
//            ForexConfigSymbolGroup symbol = symbolSeries.symbolGroupList.get(k);
//            IEngine.OrderCommand orderCommand = symbol.orderCommand;
//            BigDecimal srcAmount = new BigDecimal(symbol.standardPosition * symbolSeries.multiple * seriesMulti.prs);
//            double amount = srcAmount.divide(EAConstants.MILLION).doubleValue();
//            OrderEx orderEx = new OrderEx(getName(),LabelType.N, symbolSeries.index, index, symbol.instrument,orderCommand);
//            String label = orderEx.toStringDiff();
//            BaseOrderComment orderComment = new BaseOrderComment(index, openType, slmoney, this_tp_money, next_add_money, next_add_money_f, next_add_pause_time,first_equit,first_time);
//            String comment = orderComment.toStringDiff();
//            try {
//                ITick tick = lastTickMap.get(symbol.instrument);
//                if (tick == null) {
//                    continue;
//                }
//                if (log_print)
//                    out.println("label=" + label + ",symbol=" + symbol.instrument.name() + ",orderCommand=" + symbol.orderCommand + ",srcAmount=" + srcAmount + ",amount=" + amount + ",slippage=" + symbol0.slippage + ",comment=" + comment);
//                IOrder order = engine.submitOrder(label, symbol.instrument, symbol.orderCommand, amount, 0, symbol.slippage, 0, 0, 0, comment);
//                order.waitForUpdate(EAConstants.waitOrderTime, IOrder.State.FILLED);
//                orderList.add(order);
//            } catch (JFException e) {
//                err.println("config:"+symbolSeries+",index:"+index+" ,Order:"+k+" error:" + e.getMessage());
//            }
//        }
//        //全部开完单子后，做一个记录
//        afterAddPosition(symbolSeries,index,time);
//    }
//
//    //获取历史订单数
//    public int getHistoryOrder(BaseConfig symbolSeries,long time){
//        int hisOrderNum = 0;//历史订单
//        for (ForexConfigSymbolGroup symbol : symbolSeries.symbolGroupList) {
//            List<IOrder> histOrderList = null;
//            try {
//                histOrderList = history.getOrdersHistory(symbol.instrument, time - f_sleep_time * 60000, time);
//            } catch (JFException e) {
//                err.println(symbol.instrument.name()+" getOrdersHistory error:" + e.getMessage());
//                //如果出现错误,则返回10000,不能开单
//                return 10000;
//            }
//            if (histOrderList != null && !histOrderList.isEmpty()) {
//                for (IOrder hOrder : histOrderList) {
//                    OrderEx orderEx = new OrderEx(hOrder);
//                    if (orderEx.valid(getName()) && orderEx.configIndex == symbolSeries.index) {
//                        hisOrderNum++;
//                    }
//                }
//            }
//        }
//        return hisOrderNum;
//    }
//
//    @Override
//    public void onMessage(IMessage message) throws JFException {
//        IOrder order = message.getOrder();
//        if(order==null){
//            return;
//        }
//        OrderEx orderEx = new OrderEx(order);
//        if(!orderEx.valid(getName())){
//            return;
//        }
//        try {
//            switch (message.getType()){
//                case ORDER_FILL_OK://如果是开单,进行合单
//                    //合并订单
//                    if(is_merge && orderEx.seriesIndex>0){
//                        merge(orderEx);
//                    }
//                    break;
//                case ORDER_CLOSE_OK://如果是平仓，则记录平仓时间,作为下次暂停时间
//                    break;
//                case ORDERS_MERGE_OK://如果是合单,则进行设置新的止盈止损
//                    break;
//                case ORDER_CHANGED_OK:break;
//                //订单失败的话
//                case ORDER_FILL_REJECTED:
//                    //马上补单
//                    out.println(orderEx+" fill error:"+message.getType()+",reason="+message.getReasons());
//                    reSubmitOrder(order);
//                    break;
//                case ORDER_SUBMIT_REJECTED:
//                    out.println(orderEx+" submit error:"+message.getType()+",reason="+message.getReasons());
//                    break;
//            }
//        }catch (JFException e){
//            out.println(" error"+e);
//        }
//    }
//
//    //马上补单
//    public void reSubmitOrder(IOrder order){
//        try {
//            this.engine.submitOrder(order.getLabel(),order.getInstrument(),order.getOrderCommand(),order.getAmount(),0,10,0,0,0,order.getComment());
//        } catch (JFException e) {
//            out.println("reSubmitOrder error:"+order+","+e.getMessage());
//        }
//    }
//
//    //合并订单
//    public void merge(OrderEx orderEx) throws JFException {
//        if(orderEx==null || orderEx.order==null || orderEx.order.getState()!= IOrder.State.FILLED){
//            return;
//        }
//        IOrder order = orderEx.order;
//        List<IOrder> orderList = engine.getOrders();
//        Set<IOrder> mergeOrders = new HashSet<>();
//        if(orderList!=null){
//            for(IOrder oldOrder:orderList){
//                OrderEx oldOrderEx = new OrderEx(oldOrder);
//                if(oldOrderEx.valid(getName())
//                        && oldOrderEx.configIndex.equals(orderEx.configIndex)
//                        && oldOrder.getInstrument().equals(order.getInstrument())
//                        && oldOrder.getOrderCommand().equals(order.getOrderCommand())){
//                    mergeOrders.add(oldOrder);
//                }
//            }
//        }
//        if(mergeOrders.size()>=2){
//            out.println("merge orders:"+mergeOrders);
//            OrderEx mergeOrderEx = new OrderEx(getName(),LabelType.M,orderEx.configIndex,orderEx.seriesIndex,order.getInstrument(),order.getOrderCommand());
//            engine.mergeOrders(mergeOrderEx.toStringDiff(),order.getComment(),mergeOrders);
//        }
//    }
//
//    @Override
//    public void onTick(Instrument instrument, ITick tick){
//        baseConfigList.stream()
//                .filter(x->x.valid)
//                .filter(x->x.symbolGroupList.get(0).instrument == instrument)
//                .forEach(x->begin(x,instrument,tick.getTime()));
//    }
//
//    @Override
//    protected boolean initParam() {
//        String[] strArr = {str0, str1, str2, str3, str4, str5, str6, str7, str8, str9};
//        for (int i = 0; i < strArr.length; i++) {
//            if (strArr[i] != null && strArr[i].trim().length() > 0) {
//                String[] s = strArr[i].split(",");
//                if (s != null && s.length == 5
//                        && s[0].trim().length() > 0
//                        && s[1].trim().length() > 0
//                        && s[2].trim().length() > 0
//                        && s[3].trim().length() > 0
//                        && s[4].trim().length() > 0) {
//                    Integer symbolId = Integer.parseInt(s[0]);
//                    Integer seriesId = Integer.parseInt(s[1]);
//                    Integer multiple = Integer.parseInt(s[2]);
//                    Integer fAdd = Integer.parseInt(s[3]);
//                    Integer totalsl = Integer.parseInt(s[4]);
//                    BaseConfig symbolSeries = new BaseConfig(i, symbolId, seriesId, multiple, fAdd, totalsl);
//                    baseConfigList.add(symbolSeries);
//                    symbolSeriesMap.put(symbolSeries.index,symbolSeries);
//                    closeTimeMap.put(symbolSeries.index,0L);
//                }
//            }
//        }
//        if (baseConfigList.isEmpty()) {
//            err.println("must input more the 1 config group");
//            return false;
//        }
//
//        for (BaseConfig symbolSeries : baseConfigList) {
//            getSymbolFromHttp(symbolSeries);
//            getSeriesFromHttp(symbolSeries);
//            if (!symbolSeries.seriesMultiList.isEmpty() && !symbolSeries.symbolGroupList.isEmpty()) {
//                symbolSeries.valid = true;
//                symbolSeries.print(out);
//            }
//        }
//        return true;
//
//    }
//
//    @Override
//    protected void onBarEx(Instrument instrument, Period period, IBar askBar, IBar bidBar) {
//    }
//
//    @Override
//    public void onAccount(IAccount account) throws JFException {
//    }
//
//    @Override
//    protected void open(Instrument instrument, IBar askBar, IBar bidBar) {
//    }
//
//    @Override
//    protected void setTestParamMap(Map<String, String> paramMap, BaseConfig symbolSeries) {
//        paramMap.put("configSeriesId",symbolSeries.seriesId.toStringDiff());
//        paramMap.put("configSymbolId",symbolSeries.symbolId.toStringDiff());
//    }
//
//    @Override
//    protected void setTestParameter(BaseConfig symbolSeries, JSONObject paramJSON) {
//        paramJSON.put("totalsl",symbolSeries.totalsl);
//        paramJSON.put("fAdd",symbolSeries.fAdd);
//        paramJSON.put("index",symbolSeries.index);
//        paramJSON.put("multiple",symbolSeries.multiple);
//        paramJSON.put("f_sleep_time",this.f_sleep_time);
//        paramJSON.put("sl_sleep_time",this.sl_sleep_time);
//    }
//
//}